//
//  PLISTParser.cpp
//  sad
//
//  Created by Christopher Kemsley on 2/3/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "PLISTParser.hpp"
#include "XMLParser.hpp"
#include <sstream>
#include "Log.hpp"





struct	StringAgent : public XMLParsingAgent
{
	StringAgent ()		:	XMLParsingAgent ( "string" ) { }
	
	virtual XMLParser::Offset	parse		( std::string const & file , Any & outValue , XMLParser::Offset iStart )
		{
		XMLParser::Offset	pClose	=	0 ;
		XMLParser::Offset	length	=	XMLParserHelper :: findNextClose ( file , iStart , pClose ) ;
		
		// If close wasn't found
		if ( pClose == PLISTParser::String::npos )
			return 0 ;
		
		outValue = PLISTParser::String() ;
		PLISTParser::String&	value	=	outValue.cast<PLISTParser::String> () ;
		
		value = file.substr(iStart,length) ;
		
		return iStart + length + /*"</string>"*/9 ;
		}
} ;
StringAgent _StringAgent ;






struct	ArrayAgent : public XMLParsingAgent
{
	ArrayAgent ()		:	XMLParsingAgent ( "array" ) { }
	
	virtual XMLParser::Offset	parse		( std::string const & file , Any & outValue , XMLParser::Offset iStart )
		{
		outValue = PLISTParser::Array () ;
		PLISTParser::Array & array = outValue.cast<PLISTParser::Array>() ;
		
		XMLParser::Offset i = 0 ;
		
		
		static std::string	_end	( "</" ) ;
		
		bool	ok = true ;
		
		while ( ok )
			{
			XMLParser::Offset	iNextBrace ;	// next "<" symbol
			XMLParser::Offset	iNextClose ;	// next "</" symbol
			XMLParserHelper :: findNextOpenClosePair ( file , iStart , iNextBrace , iNextClose ) ;
			
			if ( iNextClose <= iNextBrace )	// end of array?
				{
				break ;
				}
			
			// Prepare the array's value
			array . push_back ( Any() ) ;
			Any & thisEntry = array[i++] ;
			
			iStart	=	XMLParser :: parse ( file , thisEntry , iStart ) ;
			
			if ( iStart == 0 )
				{
				ok = false ;
				
				// remove the last placeholder
				array . erase ( array.end() - 1 ) ;
				}
			}
		
		static std::string endTag ( "</array>" ) ;
		iStart = file.find(endTag,iStart) ;
		if ( iStart == PLISTParser::String::npos )
			return 0 ;
		return iStart + 8 ;
		}
} ;
ArrayAgent _ArrayAgent ;






struct	DictionaryAgent : public XMLParsingAgent
{
	DictionaryAgent ()		:	XMLParsingAgent ( "dict" ) { }
	
	virtual XMLParser::Offset	parse		( std::string const & file , Any & outValue , XMLParser::Offset iStart )
		{
		outValue = PLISTParser::Dictionary () ;
		PLISTParser::Dictionary & info = outValue.cast<PLISTParser::Dictionary>() ;
		
		
		
		static std::string	_end	( "</" ) ;
		
		bool	ok = true ;
		
		while ( ok )
			{
			XMLParser::Offset	iNextBrace ;	// next "<" symbol
			XMLParser::Offset	iNextClose ;	// next "</" symbol
			XMLParser::Offset	length		=	XMLParserHelper :: findNextOpenClosePair ( file , iStart , iNextBrace , iNextClose ) ;
			
			if ( iNextClose <= iNextBrace ) // end of dict
				{
				break ;
				}
			
			
			// Get the key value
			XMLParser::Offset			keyLength	=	length - 5 ;	// "<key>
			iNextBrace					+=	5 ;				//       SomeKey</key>..."
			
			std::string		key			=	file . substr ( iNextBrace , keyLength ) ;
			
			Log::states("PLISTParser") << "Found key \"" << key << "\"" ;
			
			
			
			
			// Skip to end of key
			iStart						=	iNextClose + 6 ; // "</key>"
			
			
			
			
			// Get the value
			Any			&	value		=	info[key] ;
			XMLParser::Offset	oldStart=	iStart ;
			iStart						=	XMLParser :: parse ( file , value , iStart ) ;
			
			if ( iStart == 0 )		// Didn't find a value... but we found a key?
				{
				iStart = oldStart ;
				Log::error("PLISTParser") << "PLIST Parser found a syntax error somewhere around character " << iStart << " : " << file.substr(iStart,20) ;
				break ;
				}
			}
		
		static std::string endTag ( "</dict>" ) ;
		iStart = file.find(endTag,iStart) ;
		return iStart + 7 ;
		}
} ;
DictionaryAgent _DictionaryAgent ;









struct	RealAgent : public XMLParsingAgent
{
	RealAgent ()		:	XMLParsingAgent ( "real" ) { }
	
	virtual XMLParser::Offset	parse		( std::string const & file , Any & outValue , XMLParser::Offset iStart )
		{
		std::string			stringValue ;
		
		XMLParser::Offset	length	=	XMLParserHelper :: getImmediateString ( file , iStart , stringValue ) ;
		
		
		std::stringstream	stream		( stringValue ) ;
		PLISTParser::Real	value	=	0 ;
		stream >> value ;
		outValue		=	value ;
		
		
		return iStart + length + /*"</real>"*/7 ;
		}
} ;
RealAgent _RealAgent ;

struct	IntegerAgent : public XMLParsingAgent
{
	IntegerAgent ()		:	XMLParsingAgent ( "integer" ) { }
	
	virtual XMLParser::Offset	parse		( std::string const & file , Any & outValue , XMLParser::Offset iStart )
		{
		std::string			stringValue ;
		
		XMLParser::Offset	length	=	XMLParserHelper :: getImmediateString ( file , iStart , stringValue ) ;
		
		
		std::stringstream		stream		( stringValue ) ;
		PLISTParser::Integer	value	=	0 ;
		stream >> value ;
		outValue			=	value ;
		
		
		return iStart + length + /*"</integer>"*/10 ;
		}
} ;
IntegerAgent _IntegerAgent ;






struct	TrueAgent : public XMLParsingAgent
{
	TrueAgent ()		:	XMLParsingAgent ( "" ) { openTag="<true/>"; }
	
	virtual XMLParser::Offset	parse		( std::string const & file , Any & outValue , XMLParser::Offset iStart )
		{
		PLISTParser::Bool	value	=	true ;
		outValue		=	value ;
		
		return iStart ;
		}
} ;
TrueAgent _TrueAgent ;

struct	FalseAgent : public XMLParsingAgent
{
	FalseAgent ()		:	XMLParsingAgent ( "" ) { openTag="<false/>"; }
	
	virtual XMLParser::Offset	parse		( std::string const & file , Any & outValue , XMLParser::Offset iStart )
		{
		PLISTParser::Bool	value	=	false ;
		outValue		=	value ;
		
		return iStart ;
		}
} ;
FalseAgent _FalseAgent ;



